#include <iostream>
#include <vector>
#include <chrono>
#include <iomanip>
#include <string>
#include <fstream>
#include <map>        // map
#include <dirent.h>  // readdir
#include <cstring>
#include <hdf5/serial/H5Cpp.h>
#include <algorithm>
#include <numeric> 
#include <cmath>
#include <random>
#include "lyh.h"

void printMatrix(float * C,const int nx,const int ny)
{
  float *ic=C;
  printf(BLUE "Matrix<%d,%d>:\n" RESET,ny,nx);
  for(int i=0;i<ny;i++)
  {
    for(int j=0;j<nx;j++)
    {
      printf("%6f ",ic[j]);
    }
    ic+=nx;
    printf("\n");
  }
}
void printMatrix_int(int * C,const int nx,const int ny)
{
  int *ic=C;
  printf("Matrix<%d,%d>:\n",ny,nx);
  for(int i=0;i<ny;i++)
  {
    for(int j=0;j<nx;j++)
    {
      printf("%d ",ic[j]);
    }
    ic+=nx;
    printf("\n");
  }
}
void save_txt(float * result_device,int batch_size, int iy,int ix,std::string filename,bool is_device) {
    float* result_test;
    if(is_device){
        result_test=(float*)malloc(batch_size*iy*ix*sizeof(float));
        CHECK(cudaMemcpy(result_test, result_device, batch_size*iy*ix*sizeof(float), cudaMemcpyDeviceToHost))
    }
    else{
        result_test=result_device;
    }
    filename="result_cu/"+filename+".txt";
    std::ofstream outfile(filename);
    if (!outfile.is_open()) {
        std::cerr << "Failed to open file for writing." << std::endl;
    }
    outfile << std::fixed << std::setprecision(6);

    for (size_t b = 0; b < batch_size; ++b) {
        for (size_t i = 0; i < iy; ++i) {
            for (size_t j = 0; j < ix; ++j) {
                size_t index = b * iy * ix + i * ix + j;
                outfile << result_test[index];
                if (j < ix - 1) {
                    outfile << " ";
                }
            }
            outfile << std::endl;
        }
    }
    outfile.close();
}


void initialData_int(int* ip, int size)
{
	time_t t;
	srand((unsigned)time(&t));
	for (int i = 0; i<size; i++)
	{
		ip[i] = int(rand()&0xff);
	}
}
void initialData_lyh(float* fp,int size, int max_val,int min_val)
{
  static int count = 0;
  time_t t;
  srand((unsigned )time(&t)+count);

  for(int i=0;i<size;i++)
  {
    float scale = static_cast<float>(std::rand()) / static_cast<float>(RAND_MAX);  
    fp[i] = min_val + scale * (max_val - min_val);  
  }
  count++;
}
void initialData_int_lyh(int* ip, int size, int max_val, int min_val) {   
    for (int i = 0; i < size; i++) {  
        ip[i] = min_val + rand() % (max_val - min_val + 1);  
    }  
} 


void initDevice(int devNum)
{
  int dev = devNum;
  cudaDeviceProp deviceProp;
  CHECK(cudaGetDeviceProperties(&deviceProp,dev));
  printf(GREEN "Using device %d: %s\n" RESET ,dev,deviceProp.name);
  CHECK(cudaSetDevice(dev));

}
void checkResult(float * hostRef,float * gpuRef,const int N)
{
  double epsilon=1.0E-8;
  for(int i=0;i<N;i++)
  {
    if(abs(hostRef[i]-gpuRef[i])>epsilon)
    {
      printf("Results don\'t match!\n");
      printf("%f(hostRef[%d] )!= %f(gpuRef[%d])\n",hostRef[i],i,gpuRef[i],i);
      return;
    }
  }
  printf(GREEN "Check result success!\n" RESET);
}

std::vector<float> read_temp_point(std::string filename)
{
    std::ifstream file(filename);
    if (!file.is_open()) {
        std::cerr << "无法打开文件" << std::endl;
    }
    std::vector<float> points;
    std::string line;
    while (std::getline(file, line)) {
        std::istringstream iss(line);
        float x, y, z;
        if (!(iss >> x >> y >> z)) {
            std::cerr << "读取数据时出错" << std::endl;
        }
        points.push_back(x);
        points.push_back(y);
        points.push_back(z);
    }
    file.close();
    return points;
}

// std::vector<float> read_param(const std::string& filepath) {
//     std::vector<float> data;
//     std::ifstream file(filepath);
//     if (file.is_open()) {
//         float value;
//         while (file >> value) {
//             data.push_back(value);
//         }
//         file.close();
//     } else {
//         std::cerr << "Unable to open file: " << filepath << std::endl;
//     }
//     return data;
// }
// std::vector<std::string> get_files_in_directory(const std::string& dir) {
//     std::vector<std::string> files;
//     DIR* dp;
//     struct dirent* entry;
//     if ((dp = opendir(dir.c_str())) != NULL) {
//         while ((entry = readdir(dp)) != NULL) {
//             std::string filename = entry->d_name;
//             if (filename.find(".txt") != std::string::npos) {
//                 files.push_back(filename);
//             }
//         }
//         closedir(dp);
//     } else {
//         perror("opendir");
//     }
//     return files;
// }
// std::map<std::string, std::vector<float>> read_params(std::string dir) {
//     std::map<std::string, std::vector<float>> params;
//     std::vector<std::string> param_files = get_files_in_directory(dir);
//     for (const auto& file : param_files) {
//         std::string filename = file.substr(0, file.find_last_of(".")); // 获取不带扩展名的文件名
//         params[filename] = read_param(dir + "/" + file);
//         // std::cout << filename << " " << params[filename].size() << std::endl;
//     }
//     return params;
// }

using namespace H5;
void read_h5_file(const std::string& file_path, std::vector<std::vector<float>>& list_of_points, std::vector<int>& list_of_labels) {
    try {
        H5File file(file_path, H5F_ACC_RDONLY);
        std::vector<std::string> dataset_names;
        hsize_t num_objs = file.getNumObjs();
        for (hsize_t i = 0; i < num_objs; i++) {
            dataset_names.push_back(file.getObjnameByIdx(i));
        }
        for (const auto& name : dataset_names) {
            DataSet dataset = file.openDataSet(name + "/points");
            DataSpace dataspace = dataset.getSpace();
            hsize_t dims[2];
            dataspace.getSimpleExtentDims(dims, NULL);
            std::vector<float> points(dims[0] * dims[1]);
            dataset.read(points.data(), PredType::NATIVE_FLOAT);
            list_of_points.push_back(points);
            Attribute label_attr = file.openGroup(name).openAttribute("label");
            int label;
            label_attr.read(PredType::NATIVE_INT, &label);
            list_of_labels.push_back(label);
        }
    } catch (FileIException& error) {
        error.printErrorStack();
    } catch (DataSetIException& error) {
        error.printErrorStack();
    } catch (DataSpaceIException& error) {
        error.printErrorStack();
    } catch (DataTypeIException& error) {
        error.printErrorStack();
    }
}
